IzpÄtiet, kÄ JavaScript iteratoru palÄ«gi uzlabo resursu pÄrvaldÄ«bu straumÄtu datu apstrÄdÄ. ApgÅ«stiet optimizÄcijas tehnikas efektÄ«vÄm un mÄrogojamÄm lietotnÄm.
JavaScript Iteratoru PalÄ«gu Resursu PÄrvaldÄ«ba: Straumju Resursu OptimizÄcija
MÅ«sdienu JavaScript izstrÄde bieži ietver darbu ar datu straumÄm. Vai tÄ bÅ«tu lielu failu apstrÄde, reÄllaika datu plÅ«smu pÄrvaldÄ«ba vai API atbilžu apstrÄde, efektÄ«va resursu pÄrvaldÄ«ba straumju apstrÄdes laikÄ ir izŔķiroÅ”a veiktspÄjai un mÄrogojamÄ«bai. Iteratoru palÄ«gi, kas tika ieviesti ar ES2015 un uzlaboti ar asinhronajiem iteratoriem un Ä£eneratoriem, nodroÅ”ina jaudÄ«gus rÄ«kus Ŕī izaicinÄjuma risinÄÅ”anai.
Izpratne par Iteratoriem un Ģeneratoriem
Pirms iedziļinÄties resursu pÄrvaldÄ«bÄ, Ä«si atkÄrtosim, kas ir iteratori un Ä£eneratori.
Iteratori ir objekti, kas definÄ secÄ«bu un metodi, kÄ piekļūt tÄs elementiem pa vienam. Tie atbilst iteratora protokolam, kas prasa next() metodi, kura atgriež objektu ar divÄm Ä«paŔībÄm: value (nÄkamais elements secÄ«bÄ) un done (bÅ«la vÄrtÄ«ba, kas norÄda, vai secÄ«ba ir pabeigta).
Ä¢eneratori ir Ä«paÅ”as funkcijas, kuras var apturÄt un atsÄkt, ļaujot tÄm laika gaitÄ radÄ«t vÄrtÄ«bu sÄriju. Tie izmanto yield atslÄgvÄrdu, lai atgrieztu vÄrtÄ«bu un apturÄtu izpildi. Kad Ä£eneratora next() metode tiek izsaukta vÄlreiz, izpilde atsÄkas no tÄs vietas, kur tÄ tika pÄrtraukta.
PiemÄrs:
function* numberGenerator(limit) {
for (let i = 0; i <= limit; i++) {
yield i;
}
}
const generator = numberGenerator(3);
console.log(generator.next()); // Izvade: { value: 0, done: false }
console.log(generator.next()); // Izvade: { value: 1, done: false }
console.log(generator.next()); // Izvade: { value: 2, done: false }
console.log(generator.next()); // Izvade: { value: 3, done: false }
console.log(generator.next()); // Izvade: { value: undefined, done: true }
Iteratoru PalÄ«gi: Straumju ApstrÄdes VienkÄrÅ”oÅ”ana
Iteratoru palÄ«gi ir metodes, kas pieejamas iteratoru prototipos (gan sinhronajos, gan asinhronajos). Tie ļauj veikt bieži sastopamas operÄcijas ar iteratoriem kodolÄ«gÄ un deklaratÄ«vÄ veidÄ. Å Ä«s operÄcijas ietver elementu pÄrveidoÅ”anu, filtrÄÅ”anu, reducÄÅ”anu un citas.
Galvenie iteratoru palīgi ietver:
map(): PÄrveido katru iteratora elementu.filter(): Atlasa elementus, kas atbilst nosacÄ«jumam.reduce(): AkumulÄ elementus vienÄ vÄrtÄ«bÄ.take(): PaÅem pirmos N iteratora elementus.drop(): Izlaiž pirmos N iteratora elementus.forEach(): Izpilda norÄdÄ«to funkciju vienreiz katram elementam.toArray(): SavÄc visus elementus masÄ«vÄ.
Lai gan stingrÄkajÄ nozÄ«mÄ tÄs nav tehniski *iteratoru* palÄ«gmetodes (jo tÄs ir metodes uz pamatÄ esoÅ”Ä *iterÄjamÄ* objekta, nevis *iteratora*), masÄ«vu metodes, piemÄram, Array.from() un izvÄrÅ”anas sintakse (...), arÄ« var tikt efektÄ«vi izmantotas ar iteratoriem, lai tos pÄrvÄrstu masÄ«vos tÄlÄkai apstrÄdei, apzinoties, ka tas prasa visu elementu ielÄdi atmiÅÄ vienlaicÄ«gi.
Å ie palÄ«gi nodroÅ”ina funkcionÄlÄku un lasÄmÄku straumju apstrÄdes stilu.
Resursu PÄrvaldÄ«bas IzaicinÄjumi Straumju ApstrÄdÄ
StrÄdÄjot ar datu straumÄm, rodas vairÄki resursu pÄrvaldÄ«bas izaicinÄjumi:
- AtmiÅas patÄriÅÅ”: Lielu straumju apstrÄde var novest pie pÄrmÄrÄ«ga atmiÅas patÄriÅa, ja to neveic uzmanÄ«gi. Visas straumes ielÄde atmiÅÄ pirms apstrÄdes bieži ir nepraktiska.
- Failu apstrÄdÄtÄji (handles): Lasot datus no failiem, ir bÅ«tiski pareizi aizvÄrt failu apstrÄdÄtÄjus, lai izvairÄ«tos no resursu noplÅ«des.
- TÄ«kla savienojumi: LÄ«dzÄ«gi kÄ failu apstrÄdÄtÄji, tÄ«kla savienojumi ir jÄaizver, lai atbrÄ«votu resursus un novÄrstu savienojumu izsmelÅ”anu. Tas ir Ä«paÅ”i svarÄ«gi, strÄdÄjot ar API vai web ligzdÄm.
- VienlaicÄ«gums (Concurrency): VienlaicÄ«gu straumju vai paralÄlas apstrÄdes pÄrvaldÄ«ba var radÄ«t sarežģījumus resursu pÄrvaldÄ«bÄ, prasot rÅ«pÄ«gu sinhronizÄciju un koordinÄciju.
- Kļūdu apstrÄde: NegaidÄ«tas kļūdas straumju apstrÄdes laikÄ var atstÄt resursus nekonsekventÄ stÄvoklÄ«, ja tÄs netiek pienÄcÄ«gi apstrÄdÄtas. Stabila kļūdu apstrÄde ir izŔķiroÅ”a, lai nodroÅ”inÄtu pareizu tÄ«rīŔanu.
ApskatÄ«sim stratÄÄ£ijas Å”o izaicinÄjumu risinÄÅ”anai, izmantojot iteratoru palÄ«gus un citas JavaScript tehnikas.
StratÄÄ£ijas Straumju Resursu OptimizÄcijai
1. SlinkÄ IzvÄrtÄÅ”ana (Lazy Evaluation) un Ä¢eneratori
Ä¢eneratori nodroÅ”ina slinko izvÄrtÄÅ”anu, kas nozÄ«mÄ, ka vÄrtÄ«bas tiek radÄ«tas tikai tad, kad tÄs ir nepiecieÅ”amas. Tas var ievÄrojami samazinÄt atmiÅas patÄriÅu, strÄdÄjot ar lielÄm straumÄm. KombinÄcijÄ ar iteratoru palÄ«giem jÅ«s varat izveidot efektÄ«vus konveijerus, kas apstrÄdÄ datus pÄc pieprasÄ«juma.
PiemÄrs: Liela CSV faila apstrÄde (Node.js vidÄ):
const fs = require('fs');
const readline = require('readline');
async function* csvLineGenerator(filePath) {
const fileStream = fs.createReadStream(filePath);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
try {
for await (const line of rl) {
yield line;
}
} finally {
// NodroÅ”ina, ka faila straume tiek aizvÄrta, pat kļūdu gadÄ«jumÄ
fileStream.close();
}
}
async function processCSV(filePath) {
const lines = csvLineGenerator(filePath);
let processedCount = 0;
for await (const line of lines) {
// ApstrÄdÄ katru rindu, neielÄdÄjot visu failu atmiÅÄ
const data = line.split(',');
console.log(`ApstrÄdÄ: ${data[0]}`);
processedCount++;
// SimulÄjam nelielu apstrÄdes aizkavi
await new Promise(resolve => setTimeout(resolve, 10)); // SimulÄ I/O vai CPU darbu
}
console.log(`ApstrÄdÄtas ${processedCount} rindas.`);
}
// LietoÅ”anas piemÄrs
const filePath = 'large_data.csv'; // AizstÄjiet ar savu faktisko faila ceļu
processCSV(filePath).catch(err => console.error("Kļūda, apstrÄdÄjot CSV:", err));
Skaidrojums:
- Funkcija
csvLineGeneratorizmantofs.createReadStreamunreadline.createInterface, lai lasÄ«tu CSV failu rindu pa rindai. - AtslÄgvÄrds
yieldatgriež katru rindu, tiklÄ«dz tÄ tiek nolasÄ«ta, apturot Ä£eneratoru lÄ«dz nÄkamÄs rindas pieprasÄ«jumam. - Funkcija
processCSViterÄ cauri rindÄm, izmantojotfor await...ofciklu, apstrÄdÄjot katru rindu, neielÄdÄjot visu failu atmiÅÄ. - Bloks
finallyÄ£eneratorÄ nodroÅ”ina, ka faila straume tiek aizvÄrta, pat ja apstrÄdes laikÄ rodas kļūda. Tas ir *kritiski* svarÄ«gi resursu pÄrvaldÄ«bai.fileStream.close()izmantoÅ”ana nodroÅ”ina tieÅ”u kontroli pÄr resursu. - Ir iekļauta simulÄta apstrÄdes aizkave, izmantojot `setTimeout`, lai attÄlotu reÄlus I/O vai CPU-intensÄ«vus uzdevumus, kas pastiprina slinkÄs izvÄrtÄÅ”anas nozÄ«mi.
2. Asinhronie Iteratori
Asinhronie iteratori (async iterators) ir paredzÄti darbam ar asinhroniem datu avotiem, piemÄram, API galapunktiem vai datu bÄzes vaicÄjumiem. Tie ļauj apstrÄdÄt datus, tiklÄ«dz tie kļūst pieejami, novÄrÅ”ot bloÄ·ÄjoÅ”as operÄcijas un uzlabojot reaÄ£ÄtspÄju.
PiemÄrs: Datu ielÄde no API, izmantojot asinhrono iteratoru:
async function* apiDataGenerator(url) {
let page = 1;
while (true) {
const response = await fetch(`${url}?page=${page}`);
if (!response.ok) {
throw new Error(`HTTP kļūda! statuss: ${response.status}`);
}
const data = await response.json();
if (data.length === 0) {
break; // Vairs nav datu
}
for (const item of data) {
yield item;
}
page++;
// SimulÄjam pieprasÄ«jumu ierobežoÅ”anu, lai nepÄrslogotu serveri
await new Promise(resolve => setTimeout(resolve, 500));
}
}
async function processAPIdata(url) {
const dataStream = apiDataGenerator(url);
try {
for await (const item of dataStream) {
console.log("ApstrÄdÄ vienumu:", item);
// ApstrÄdÄ vienumu
}
} catch (error) {
console.error("Kļūda, apstrÄdÄjot API datus:", error);
}
}
// LietoÅ”anas piemÄrs
const apiUrl = 'https://example.com/api/data'; // AizstÄjiet ar savu faktisko API galapunktu
processAPIdata(apiUrl).catch(err => console.error("KopÄjÄ kļūda:", err));
Skaidrojums:
- Funkcija
apiDataGeneratorielÄdÄ datus no API galapunkta, lapojot cauri rezultÄtiem. - AtslÄgvÄrds
awaitnodroÅ”ina, ka katrs API pieprasÄ«jums tiek pabeigts pirms nÄkamÄ izsaukÅ”anas. - AtslÄgvÄrds
yieldatgriež katru vienumu, tiklÄ«dz tas ir ielÄdÄts, apturot Ä£eneratoru lÄ«dz nÄkamÄ vienuma pieprasÄ«jumam. - Ir iekļauta kļūdu apstrÄde, lai pÄrbaudÄ«tu neveiksmÄ«gas HTTP atbildes.
- PieprasÄ«jumu ierobežoÅ”ana ir simulÄta, izmantojot
setTimeout, lai novÄrstu API servera pÄrslogoÅ”anu. TÄ ir *labÄkÄ prakse* API integrÄcijÄ. - Å
emiet vÄrÄ, ka Å”ajÄ piemÄrÄ tÄ«kla savienojumus netieÅ”i pÄrvalda
fetchAPI. SarežģītÄkos scenÄrijos (piemÄram, izmantojot pastÄvÄ«gas web ligzdas) varÄtu bÅ«t nepiecieÅ”ama tieÅ”a savienojumu pÄrvaldÄ«ba.
3. Vienlaicīguma IerobežoŔana
ApstrÄdÄjot straumes vienlaicÄ«gi, ir svarÄ«gi ierobežot vienlaicÄ«go operÄciju skaitu, lai izvairÄ«tos no resursu pÄrslogoÅ”anas. JÅ«s varat izmantot tehnikas, piemÄram, semaforus vai uzdevumu rindas, lai kontrolÄtu vienlaicÄ«gumu.
PiemÄrs: VienlaicÄ«guma ierobežoÅ”ana ar semaforu:
class Semaphore {
constructor(max) {
this.max = max;
this.count = 0;
this.waiting = [];
}
async acquire() {
if (this.count < this.max) {
this.count++;
return;
}
return new Promise(resolve => {
this.waiting.push(resolve);
});
}
release() {
this.count--;
if (this.waiting.length > 0) {
const resolve = this.waiting.shift();
resolve();
this.count++; // Palielina skaitÄ«tÄju atpakaļ par atbrÄ«voto uzdevumu
}
}
}
async function processItem(item, semaphore) {
await semaphore.acquire();
try {
console.log(`ApstrÄdÄ vienumu: ${item}`);
// SimulÄjam kÄdu asinhronu operÄciju
await new Promise(resolve => setTimeout(resolve, 200));
console.log(`Pabeigta vienuma apstrÄde: ${item}`);
} finally {
semaphore.release();
}
}
async function processStream(data, concurrency) {
const semaphore = new Semaphore(concurrency);
const promises = data.map(async item => {
await processItem(item, semaphore);
});
await Promise.all(promises);
console.log("Visi vienumi apstrÄdÄti.");
}
// LietoÅ”anas piemÄrs
const data = Array.from({ length: 10 }, (_, i) => i + 1);
const concurrencyLevel = 3;
processStream(data, concurrencyLevel).catch(err => console.error("Kļūda, apstrÄdÄjot straumi:", err));
Skaidrojums:
- Klase
Semaphoreierobežo vienlaicÄ«go operÄciju skaitu. - Metode
acquire()bloÄ·Ä izpildi, lÄ«dz ir pieejama atļauja. - Metode
release()atbrÄ«vo atļauju, ļaujot turpinÄt citu operÄciju. - Funkcija
processItem()iegÅ«st atļauju pirms vienuma apstrÄdes un atbrÄ«vo to pÄc tam. Bloksfinally*garantÄ* atbrÄ«voÅ”anu, pat ja rodas kļūdas. - Funkcija
processStream()apstrÄdÄ datu straumi ar norÄdÄ«to vienlaicÄ«guma lÄ«meni. - Å is piemÄrs demonstrÄ bieži sastopamu modeli resursu izmantoÅ”anas kontrolei asinhronÄ JavaScript kodÄ.
4. Kļūdu ApstrÄde un Resursu TÄ«rīŔana
Stabila kļūdu apstrÄde ir bÅ«tiska, lai nodroÅ”inÄtu, ka resursi tiek pareizi atbrÄ«voti kļūdu gadÄ«jumÄ. Izmantojiet try...catch...finally blokus, lai apstrÄdÄtu izÅÄmumus un atbrÄ«votu resursus finally blokÄ. finally bloks tiek izpildÄ«ts *vienmÄr*, neatkarÄ«gi no tÄ, vai tiek izmests izÅÄmums.
PiemÄrs: Resursu tÄ«rīŔanas nodroÅ”inÄÅ”ana ar try...catch...finally:
const fs = require('fs');
async function processFile(filePath) {
let fileHandle = null;
try {
fileHandle = await fs.promises.open(filePath, 'r');
const stream = fileHandle.createReadStream();
for await (const chunk of stream) {
console.log(`ApstrÄdÄ datu daļu: ${chunk.toString()}`);
// ApstrÄdÄ datu daļu
}
} catch (error) {
console.error(`Kļūda, apstrÄdÄjot failu: ${error}`);
// ApstrÄdÄ kļūdu
} finally {
if (fileHandle) {
try {
await fileHandle.close();
console.log('Faila apstrÄdÄtÄjs veiksmÄ«gi aizvÄrts.');
} catch (closeError) {
console.error('Kļūda, aizverot faila apstrÄdÄtÄju:', closeError);
}
}
}
}
// LietoÅ”anas piemÄrs
const filePath = 'data.txt'; // AizstÄjiet ar savu faktisko faila ceļu
// Izveidojam testa failu
fs.writeFileSync(filePath, 'Å ie ir daži parauga dati.\nAr vairÄkÄm rindÄm.');
processFile(filePath).catch(err => console.error("KopÄjÄ kļūda:", err));
Skaidrojums:
- Funkcija
processFile()atver failu, nolasa tÄ saturu un apstrÄdÄ katru datu daļu. - Bloks
try...catch...finallynodroÅ”ina, ka faila apstrÄdÄtÄjs tiek aizvÄrts, pat ja apstrÄdes laikÄ rodas kļūda. - Bloks
finallypÄrbauda, vai faila apstrÄdÄtÄjs ir atvÄrts, un, ja nepiecieÅ”ams, to aizver. Tas ietver arÄ« *savu*try...catchbloku, lai apstrÄdÄtu iespÄjamÄs kļūdas paÅ”Ä aizvÄrÅ”anas operÄcijÄ. Å Ä« ligzdotÄ kļūdu apstrÄde ir svarÄ«ga, lai nodroÅ”inÄtu, ka tÄ«rīŔanas operÄcija ir stabila. - PiemÄrs demonstrÄ pÄrdomÄtas resursu tÄ«rīŔanas nozÄ«mi, lai novÄrstu resursu noplÅ«des un nodroÅ”inÄtu jÅ«su lietotnes stabilitÄti.
5. TransformÄcijas Straumju IzmantoÅ”ana
TransformÄcijas straumes ļauj apstrÄdÄt datus, kamÄr tie plÅ«st caur straumi, pÄrveidojot tos no viena formÄta citÄ. TÄs ir Ä«paÅ”i noderÄ«gas tÄdiem uzdevumiem kÄ saspieÅ”ana, Å”ifrÄÅ”ana vai datu validÄcija.
PiemÄrs: Datu straumes saspieÅ”ana, izmantojot zlib (Node.js vidÄ):
const fs = require('fs');
const zlib = require('zlib');
const { pipeline } = require('stream');
const { promisify } = require('util');
const pipe = promisify(pipeline);
async function compressFile(inputPath, outputPath) {
const gzip = zlib.createGzip();
const source = fs.createReadStream(inputPath);
const destination = fs.createWriteStream(outputPath);
try {
await pipe(source, gzip, destination);
console.log('SaspieŔana pabeigta.');
} catch (err) {
console.error('SaspieÅ”anas laikÄ radÄs kļūda:', err);
}
}
// LietoÅ”anas piemÄrs
const inputFilePath = 'large_input.txt';
const outputFilePath = 'large_input.txt.gz';
// Izveidojam lielu testa failu
const largeData = Array.from({ length: 1000000 }, (_, i) => `Rinda ${i}\n`).join('');
fs.writeFileSync(inputFilePath, largeData);
compressFile(inputFilePath, outputFilePath).catch(err => console.error("KopÄjÄ kļūda:", err));
Skaidrojums:
- Funkcija
compressFile()izmantozlib.createGzip(), lai izveidotu gzip saspieŔanas straumi. - Funkcija
pipeline()savieno avota straumi (ievades fails), transformÄcijas straumi (gzip saspieÅ”ana) un mÄrÄ·a straumi (izvades fails). Tas vienkÄrÅ”o straumju pÄrvaldÄ«bu un kļūdu izplatīŔanu. - Ir iekļauta kļūdu apstrÄde, lai notvertu jebkÄdas kļūdas, kas rodas saspieÅ”anas procesÄ.
- TransformÄcijas straumes ir jaudÄ«gs veids, kÄ apstrÄdÄt datus modulÄrÄ un efektÄ«vÄ veidÄ.
- Funkcija
pipelinenodroÅ”ina pareizu tÄ«rīŔanu (straumju aizvÄrÅ”anu), ja procesa laikÄ rodas kļūda. Tas ievÄrojami vienkÄrÅ”o kļūdu apstrÄdi, salÄ«dzinot ar manuÄlu straumju savienoÅ”anu.
LabÄkÄs Prakses JavaScript Straumju Resursu OptimizÄcijai
- Izmantojiet slinko izvÄrtÄÅ”anu: Izmantojiet Ä£eneratorus un asinhronos iteratorus, lai apstrÄdÄtu datus pÄc pieprasÄ«juma un samazinÄtu atmiÅas patÄriÅu.
- Ierobežojiet vienlaicÄ«gumu: KontrolÄjiet vienlaicÄ«go operÄciju skaitu, lai izvairÄ«tos no resursu pÄrslogoÅ”anas.
- PÄrdomÄti apstrÄdÄjiet kļūdas: Izmantojiet
try...catch...finallyblokus, lai apstrÄdÄtu izÅÄmumus un nodroÅ”inÄtu pareizu resursu tÄ«rīŔanu. - TieÅ”i aizveriet resursus: NodroÅ”iniet, ka failu apstrÄdÄtÄji, tÄ«kla savienojumi un citi resursi tiek aizvÄrti, kad tie vairs nav nepiecieÅ”ami.
- PÄrraugiet resursu izmantoÅ”anu: Izmantojiet rÄ«kus, lai pÄrraudzÄ«tu atmiÅas, CPU un citu resursu metriku izmantoÅ”anu, lai identificÄtu potenciÄlÄs vÄjÄs vietas.
- IzvÄlieties pareizos rÄ«kus: IzvÄlieties atbilstoÅ”as bibliotÄkas un ietvarus savÄm specifiskajÄm straumju apstrÄdes vajadzÄ«bÄm. PiemÄram, apsveriet tÄdu bibliotÄku kÄ Highland.js vai RxJS izmantoÅ”anu sarežģītÄkÄm straumju manipulÄcijas iespÄjÄm.
- Apsveriet pretspiedienu (Backpressure): StrÄdÄjot ar straumÄm, kur ražotÄjs ir ievÄrojami ÄtrÄks par patÄrÄtÄju, ieviest pretspiediena mehÄnismus, lai novÄrstu patÄrÄtÄja pÄrslogoÅ”anu. Tas var ietvert datu buferÄÅ”anu vai tÄdu tehniku kÄ reaktÄ«vo straumju izmantoÅ”anu.
- ProfilÄjiet savu kodu: Izmantojiet profilÄÅ”anas rÄ«kus, lai identificÄtu veiktspÄjas vÄjÄs vietas savÄ straumju apstrÄdes konveijerÄ. Tas var palÄ«dzÄt optimizÄt kodu maksimÄlai efektivitÄtei.
- Rakstiet vienÄ«btestus (Unit Tests): RÅ«pÄ«gi testÄjiet savu straumju apstrÄdes kodu, lai nodroÅ”inÄtu, ka tas pareizi apstrÄdÄ dažÄdus scenÄrijus, ieskaitot kļūdu nosacÄ«jumus.
- DokumentÄjiet savu kodu: Skaidri dokumentÄjiet savu straumju apstrÄdes loÄ£iku, lai citiem (un sev nÄkotnÄ) bÅ«tu vieglÄk to saprast un uzturÄt.
NoslÄgums
EfektÄ«va resursu pÄrvaldÄ«ba ir izŔķiroÅ”a, lai veidotu mÄrogojamas un veiktspÄjÄ«gas JavaScript lietotnes, kas apstrÄdÄ datu straumes. Izmantojot iteratoru palÄ«gus, Ä£eneratorus, asinhronos iteratorus un citas tehnikas, jÅ«s varat izveidot stabilus un efektÄ«vus straumju apstrÄdes konveijerus, kas samazina atmiÅas patÄriÅu, novÄrÅ” resursu noplÅ«des un pÄrdomÄti apstrÄdÄ kļūdas. Atcerieties pÄrraudzÄ«t savas lietotnes resursu izmantoÅ”anu un profilÄt kodu, lai identificÄtu potenciÄlÄs vÄjÄs vietas un optimizÄtu veiktspÄju. Sniegtie piemÄri demonstrÄ Å”o koncepciju praktisku pielietojumu gan Node.js, gan pÄrlÅ«kprogrammas vidÄs, ļaujot jums pielietot Ŕīs tehnikas plaÅ”Ä reÄlÄs pasaules scenÄriju klÄstÄ.